/***************************************************
 ** @Desc : This file for 用户信息数据模型
 ** @Time : 2019.03.30 16:24 
 ** @Author : Joker
 ** @File : user_info
 ** @Last Modified by : Joker
 ** @Last Modified time: 2019.03.30 16:24
 ** @Software: GoLand
****************************************************/
package models

import (
	"github.com/astaxie/beego/orm"
	"recharge/sys"
	"recharge/utils"
	"strings"
)

var globalMethod = utils.GlobalMethod{}

//用户信息结构
type UserInfo struct {
	Id         int `orm:"pk"`
	Version    int    //版本
	Mobile     string //手机号
	Status     int    //状态
	EditTime   string
	CreateTime string
	UserName   string //用户名
	LoginName  string //用户登录名
	LoginPwd   string //登录密码
	Salt       string //密码盐

	//权限1:VIP用户;2:普通用户;3:对接用户
	//TODO:VIP用户能使用B2C转账功能，无法添加用户
	Authority int

	TotalAmount  float64                   //总金额
	UsableAmount float64                   //可用金额
	FrozenAmount float64                   //冻结金额
	ApiKey       string `orm:"type(text)"` //对接用户的api密钥
	PayFee       float64                   //代付单笔手续费,元
	RechargeFee  float64                   //充值单笔手续费,元
	RechargeRate float64                   //充值单笔费率,千分之几

	PayByRecord      float64 `orm:"-"` //根据账单算提现
	RechargeByRecord float64 `orm:"-"` //根据账单算充值
	TransferByRecord float64 `orm:"-"` //根据账单算转账
	ProfitByRecord   float64 `orm:"-"` //根据账单算利润
	BalanceByRecord  float64 `orm:"-"` //根据账单算余额
	HandleAddition   float64 `orm:"-"` //手动加款
	HandleDeduction  float64 `orm:"-"` //手动减款

	PayByRecordToday      float64 `orm:"-"` //根据账单算今日提现
	RechargeByRecordToday float64 `orm:"-"` //根据账单算今日充值
	TransferByRecordToday float64 `orm:"-"` //根据账单算今日转账
	ProfitByRecordToday   float64 `orm:"-"` //根据账单算今日利润
}

func (*UserInfo) TableEngine() string {
	return "INNODB"
}

func (*UserInfo) TableName() string {
	return UserInfoTBName()
}

/* *
 * @Description: 添加用户信息
 * @Author: Joker
 * @Date: 2019.04.01 11:43
 * @Param: sr: 用户信息
 * @return: int: 判断成功的标识
 * @return: int64:	在表中哪一行插入
 **/
func (*UserInfo) InsertUsers(sr UserInfo) (int, int64) {
	om := orm.NewOrm()
	in, _ := om.QueryTable(UserInfoTBName()).PrepareInsert()
	id, err := in.Insert(&sr)
	if err != nil {
		sys.LogError("InsertUsers failed to insert for: ", err)
		return utils.FAILED_FLAG, id
	}
	return utils.SUCCESS_FLAG, id
}

//读取单个用户信息通过登录账号
func (*UserInfo) SelectOneUser(loginName string) (conf UserInfo) {
	om := orm.NewOrm()
	err := om.QueryTable(UserInfoTBName()).Filter("login_name", loginName).One(&conf)
	if err != nil {
		sys.LogError("SelectOneUser failed to select user: ", err)
	}
	return conf
}

//判断当前登录用户是否存在
func (*UserInfo) UserIsExit(uName string) bool {
	om := orm.NewOrm()
	return om.QueryTable(UserInfoTBName()).Filter("login_name", uName).Exist()
}

// 修改用户信息
func (*UserInfo) UpdateUserInfo(info UserInfo) int {
	om := orm.NewOrm()
	_, err := om.QueryTable(UserInfoTBName()).Filter("login_name", info.LoginName).Update(orm.Params{
		"version":       orm.ColValue(orm.ColAdd, 1),
		"mobile":        info.Mobile,
		"edit_time":     info.EditTime,
		"user_name":     info.UserName,
		"status":        info.Status,
		"login_pwd":     info.LoginPwd,
		"salt":          info.Salt,
		"authority":     info.Authority,
		"total_amount":  info.TotalAmount,
		"usable_amount": info.UsableAmount,
		"frozen_amount": info.FrozenAmount,
		"api_key":       info.ApiKey,
		"pay_fee":       info.PayFee,
		"recharge_fee":  info.RechargeFee,
		"recharge_rate": info.RechargeRate,
	})
	if err != nil {
		sys.LogError("UpdateUserInfo failed to update for:", err)
		return utils.FAILED_FLAG
	}
	return utils.SUCCESS_FLAG
}

/*查询分页*/
func (*UserInfo) SelectUserListPage(params map[string]interface{}, limit, offset int) (list []UserInfo) {
	om := orm.NewOrm()
	qt := om.QueryTable(UserInfoTBName())
	qt = qt.Exclude("authority", "-1")
	for k, v := range params {
		if v != "" {
			qt = qt.Filter(k, v)
		}
	}
	_, err := qt.OrderBy("-edit_time").Limit(limit, offset).All(&list)
	if err != nil {
		sys.LogError("SelectUserListPage failed to query paging for: ", err)
	}
	return list
}

func (*UserInfo) SelectUserPageCount(params map[string]interface{}) int {
	om := orm.NewOrm()
	qt := om.QueryTable(UserInfoTBName())
	qt = qt.Exclude("authority", "-1")
	for k, v := range params {
		if v != "" {
			qt = qt.Filter(k, v)
		}
	}
	cnt, err := qt.Count()
	if err != nil {
		sys.LogError("SelectUserPageCount failed to count for:", err)
	}
	return int(cnt)
}

// 通过用户名查询用户信息
func (*UserInfo) SelectOneUserByUserName(loginName string) (conf UserInfo) {
	om := orm.NewOrm()
	_, err := om.QueryTable(UserInfoTBName()).Exclude("authority", "-1").Filter("user_name", loginName).All(&conf)
	if err != nil {
		sys.LogError("SelectOneUserByUserName failed to select user: ", err)
	}
	return conf
}

//读取单个用户信息通过id
func (*UserInfo) SelectOneUserById(id int) (info UserInfo, err error) {
	om := orm.NewOrm()

	err = om.Raw("select * from user_info where id = ? for update", id).QueryRow(&info)
	if err != nil {
		sys.LogError("SelectOneUserById failed to select user: ", err)
		return info, err
	}

	return info, err
}

var payMdl = WithdrawRecord{}

// 用户加款
func (the *UserInfo) SelectOneUserAddition(userId int, amount float64, record RechargeRecord) int {
	om := orm.NewOrm()
	begin := om.Begin()

	defer func(interface{}) {
		if r := recover(); r != nil {
			om.Rollback()
			sys.LogEmergency("SelectOneUserAddition is panic,but it recover")
		}
	}(om)

	// 选择充值记录
	rRecord := RechargeRecord{}
	err0 := om.Raw("select * from recharge_record where re_order_id = ? for update", record.ReOrderId).QueryRow(&rRecord)
	// 判断
	if strings.Compare(utils.S, rRecord.Status) == 0 {
		om.Rollback()
		return utils.SUCCESS_FLAG
	}
	//更新充值记录
	_, flag0 := om.QueryTable(RechargeRecordTBName()).Filter("re_order_id", record.ReOrderId).Filter("merchant_no", record.MerchantNo).
		Update(orm.Params{
			"version":   orm.ColValue(orm.ColAdd, 1),
			"edit_time": record.EditTime,
			"status":    record.Status,
			"remark":    record.Remark,
		})

	// 选择用户
	info := UserInfo{}
	err := om.Raw("select * from user_info where id = ? for update", userId).QueryRow(&info)

	// 用户加款
	addAmount := amount - info.RechargeFee - amount*info.RechargeRate*0.001
	info.TotalAmount += addAmount
	info.UsableAmount += addAmount
	info.EditTime = globalMethod.GetNowTime()
	flag1 := updateSql(om, info)

	// 加款操作
	history := UserHistory{}
	history.UserId = info.Id
	history.UserName = info.UserName
	history.CreateTime = globalMethod.GetNowTime()
	history.EditTime = history.CreateTime
	history.Addition = addAmount
	history.TotalAmount = info.TotalAmount
	history.FrozenAmount = info.FrozenAmount
	history.UsableAmount = info.UsableAmount
	in, _ := om.QueryTable(UserHistoryTBName()).PrepareInsert()
	_, flag2 := in.Insert(&history)

	if begin != nil || err != nil || flag1 != nil ||
		flag2 != nil || flag0 != nil || err0 != nil {
		om.Rollback()
		sys.LogError("SelectOneUserAddition something is error: ", begin, err)
		sys.LogError("RechargeRecord:", record)
		return utils.FAILED_FLAG
	} else {
		om.Commit()
		return utils.SUCCESS_FLAG
	}
}

// 用户加款不扣充值手续费
func (the *UserInfo) SelectOneUserAdditionNotFee(userId int, amount float64, record TransferRecord) int {
	om := orm.NewOrm()
	begin := om.Begin()

	defer func(interface{}) {
		if r := recover(); r != nil {
			om.Rollback()
			sys.LogEmergency("SelectOneUserAdditionNotFee is panic,but it recover")
		}
	}(om)

	// 选择用户
	tRecord := TransferRecord{}
	err0 := om.Raw("select * from transfer_record where tr_order_id = ? for update", record.TrOrderId).QueryRow(&tRecord)
	//
	if strings.Compare(utils.S, tRecord.Status) == 0 {
		om.Rollback()
		return utils.SUCCESS_FLAG
	}
	//更新充值记录
	_, flag := om.QueryTable(TransferRecordTBName()).Filter("tr_order_id", record.TrOrderId).Filter("merchant_no", record.MerchantNo).
		Update(orm.Params{
			"version":   orm.ColValue(orm.ColAdd, 1),
			"edit_time": record.EditTime,
			"status":    record.Status,
			"remark":    record.Remark,
		})

	// 选择用户
	info := UserInfo{}
	err := om.Raw("select * from user_info where id = ? for update", userId).QueryRow(&info)

	addAmount := amount - amount*info.RechargeRate*0.001
	info.TotalAmount += addAmount
	info.UsableAmount += addAmount
	info.EditTime = globalMethod.GetNowTime()
	flag1 := updateSql(om, info)

	// 加款操作
	history := UserHistory{}
	history.UserId = info.Id
	history.UserName = info.UserName
	history.CreateTime = globalMethod.GetNowTime()
	history.EditTime = history.CreateTime
	history.Addition = addAmount
	history.TotalAmount = info.TotalAmount
	history.FrozenAmount = info.FrozenAmount
	history.UsableAmount = info.UsableAmount
	in, _ := om.QueryTable(UserHistoryTBName()).PrepareInsert()
	_, flag2 := in.Insert(&history)

	if begin != nil || err != nil || flag1 != nil ||
		flag2 != nil || flag != nil || err0 != nil {
		om.Rollback()
		sys.LogError("SelectOneUserAdditionNotFee something is error: ", begin, err)
		sys.LogError("TransferRecord:", record)
		return utils.FAILED_FLAG
	} else {
		om.Commit()
		return utils.SUCCESS_FLAG
	}
}

// 用户提现成功 减款
func (the *UserInfo) SelectOneUserDeductionForSuccess(userId int, amount float64, record WithdrawRecord) int {
	om := orm.NewOrm()
	begin := om.Begin()

	defer func(interface{}) {
		if r := recover(); r != nil {
			om.Rollback()
			sys.LogEmergency("SelectOneUserDeductionForSuccess is panic,but it recover")
		}
	}(om)

	// 选择用户记录
	wRecord := WithdrawRecord{}
	err0 := om.Raw("select * from withdraw_record where wh_order_id = ? for update", record.WhOrderId).QueryRow(&wRecord)
	// 判断记录状态
	if strings.Compare(utils.S, wRecord.Status) == 0 {
		om.Rollback()
		return utils.SUCCESS_FLAG
	}
	//更新充值记录
	_, flag := om.QueryTable(WithdrawRecordTBName()).Filter("wh_order_id", record.WhOrderId).Filter("merchant_no", record.MerchantNo).
		Update(orm.Params{
			"version":   orm.ColValue(orm.ColAdd, 1),
			"edit_time": record.EditTime,
			"status":    record.Status,
			"remark":    record.Remark,
		})

	// 选择用户
	info := UserInfo{}
	err := om.Raw("select * from user_info where id = ? for update", userId).QueryRow(&info)

	ducAmount := amount + info.PayFee
	info.FrozenAmount -= ducAmount
	info.UsableAmount -= ducAmount
	info.TotalAmount -= ducAmount
	info.EditTime = globalMethod.GetNowTime()
	flag1 := updateSql(om, info)

	// 冻结减操作
	history := UserHistory{}
	history.UserId = info.Id
	history.UserName = info.UserName
	history.CreateTime = globalMethod.GetNowTime()
	history.EditTime = history.CreateTime
	history.FrozenDed = ducAmount
	history.Deduction = ducAmount
	history.TotalAmount = info.TotalAmount
	history.FrozenAmount = info.FrozenAmount
	history.UsableAmount = info.UsableAmount
	in, _ := om.QueryTable(UserHistoryTBName()).PrepareInsert()
	_, flag2 := in.Insert(&history)

	if begin != nil || err != nil ||
		flag1 != nil || flag2 != nil ||
		flag != nil || err0 != nil {
		om.Rollback()
		sys.LogError("SelectOneUserDeductionForSuccess something is error: ", begin, err)
		sys.LogError("WithdrawRecord:", record)
		return utils.FAILED_FLAG
	} else {
		om.Commit()
		return utils.SUCCESS_FLAG
	}
}

// 判断账户可用余额
// 用户提现处理中 冻结款
func (the *UserInfo) SelectOneUserUsableAmount(userId int, amount float64, record WithdrawRecord) (bool, string) {
	om := orm.NewOrm()
	begin := om.Begin()

	defer func(interface{}) {
		if r := recover(); r != nil {
			om.Rollback()
			sys.LogEmergency("SelectOneUserUsableAmount is panic,but it recover")
		}
	}(om)

	// 选择用户
	info := UserInfo{}
	err := om.Raw("select * from user_info where id = ? for update", userId).QueryRow(&info)
	amount += info.PayFee //扣除手续费

	if info.FrozenAmount < 0 {
		om.Rollback()
		return false, "账户冻结金额非法，请联系管理员处理！"
	}

	usable := info.UsableAmount - info.FrozenAmount
	if usable < 0 {
		om.Rollback()
		return false, "账户可用余额为0"
	} else if usable < amount {
		om.Rollback()
		return false, "代付金额大于账户可提现余额"
	}

	//插入记录
	if strings.Compare(utils.S, record.Status) == 0 {
		om.Rollback()
		return false, "不能直接插入成功的记录"
	}
	flag, _ := payMdl.InsertWithdrawRecord(record)

	info.FrozenAmount += amount
	info.EditTime = globalMethod.GetNowTime()
	flag1 := updateSql(om, info)

	// 冻结加操作
	history := UserHistory{}
	history.UserId = info.Id
	history.UserName = info.UserName
	history.CreateTime = globalMethod.GetNowTime()
	history.EditTime = history.CreateTime
	history.FrozenAdd = amount
	history.TotalAmount = info.TotalAmount
	history.FrozenAmount = info.FrozenAmount
	history.UsableAmount = info.UsableAmount
	in, _ := om.QueryTable(UserHistoryTBName()).PrepareInsert()
	_, flag2 := in.Insert(&history)

	if begin != nil || err != nil || flag < 0 ||
		flag2 != nil || flag1 != nil {
		om.Rollback()
		sys.LogError("SelectOneUserUsableAmount something is error: ", begin)
		return false, begin.Error()
	} else {
		om.Commit()
		return true, ""
	}
}

// 用户提现处理中 冻结款
func (the *UserInfo) SelectOneUserFrozenSection(userId int, amount float64, record WithdrawRecord) int {
	om := orm.NewOrm()
	begin := om.Begin()

	defer func(interface{}) {
		if r := recover(); r != nil {
			om.Rollback()
			sys.LogEmergency("SelectOneUserFrozenSection is panic,but it recover")
		}
	}(om)

	//插入记录
	if strings.Compare(utils.S, record.Status) == 0 {
		om.Rollback()
		sys.LogError("SelectOneUserDeductionForFail something is error: 订单状态已成功")
		return utils.SUCCESS_FLAG
	}
	flag, _ := payMdl.InsertWithdrawRecord(record)

	// 选择用户
	info := UserInfo{}
	err := om.Raw("select * from user_info where id = ? for update", userId).QueryRow(&info)

	freAmount := amount + info.PayFee
	info.FrozenAmount += freAmount
	info.EditTime = globalMethod.GetNowTime()
	flag1 := updateSql(om, info)

	// 冻结加操作
	history := UserHistory{}
	history.UserId = info.Id
	history.UserName = info.UserName
	history.CreateTime = globalMethod.GetNowTime()
	history.EditTime = history.CreateTime
	history.FrozenAdd = freAmount
	history.TotalAmount = info.TotalAmount
	history.FrozenAmount = info.FrozenAmount
	history.UsableAmount = info.UsableAmount
	in, _ := om.QueryTable(UserHistoryTBName()).PrepareInsert()
	_, flag2 := in.Insert(&history)

	if begin != nil || err != nil ||
		flag1 != nil || flag2 != nil || flag < 0 {
		om.Rollback()
		sys.LogError("SelectOneUserFrozenSection something is error: ", begin, err)
		return utils.FAILED_FLAG
	} else {
		om.Commit()
		return utils.SUCCESS_FLAG
	}
}

// 用户提现失败 不减款
func (the *UserInfo) SelectOneUserDeductionForFail(userId int, amount float64, record WithdrawRecord) int {
	om := orm.NewOrm()
	begin := om.Begin()

	defer func(interface{}) {
		if r := recover(); r != nil {
			om.Rollback()
			sys.LogEmergency("SelectOneUserDeductionForFail is panic,but it recover")
		}
	}(om)

	// 选择用户
	wRecord := WithdrawRecord{}
	err0 := om.Raw("select * from withdraw_record where wh_order_id = ? for update", record.WhOrderId).QueryRow(&wRecord)
	//
	if strings.Compare(utils.S, wRecord.Status) == 0 {
		sys.LogError("SelectOneUserDeductionForFail something is error: 订单状态已成功")
		om.Rollback()
		return utils.SUCCESS_FLAG
	}
	//更新充值记录
	_, flag := om.QueryTable(WithdrawRecordTBName()).Filter("wh_order_id", record.WhOrderId).Filter("merchant_no", record.MerchantNo).
		Update(orm.Params{
			"version":   orm.ColValue(orm.ColAdd, 1),
			"edit_time": record.EditTime,
			"status":    record.Status,
			"remark":    record.Remark,
		})

	// 选择用户
	info := UserInfo{}
	err := om.Raw("select * from user_info where id = ? for update", userId).QueryRow(&info)

	ducAmount := amount + info.PayFee
	info.FrozenAmount -= ducAmount
	if info.FrozenAmount < 0 {
		om.Rollback()
		sys.LogError("SelectOneUserDeductionForFail something is error: 账号冻结款为负数")
		sys.LogError("WithdrawRecord:", record)
		return utils.FAILED_FLAG
	}
	info.EditTime = globalMethod.GetNowTime()
	flag1 := updateSql(om, info)

	// 冻结减操作
	history := UserHistory{}
	history.UserId = info.Id
	history.UserName = info.UserName
	history.CreateTime = globalMethod.GetNowTime()
	history.EditTime = history.CreateTime
	history.FrozenDed = ducAmount
	history.TotalAmount = info.TotalAmount
	history.FrozenAmount = info.FrozenAmount
	history.UsableAmount = info.UsableAmount
	in, _ := om.QueryTable(UserHistoryTBName()).PrepareInsert()
	_, flag2 := in.Insert(&history)

	if begin != nil || err != nil ||
		flag1 != nil || flag2 != nil ||
		flag != nil || err0 != nil {
		om.Rollback()
		sys.LogError("SelectOneUserDeductionForFail something is error: ", begin, err)
		sys.LogError("WithdrawRecord:", record)
		return utils.FAILED_FLAG
	} else {
		om.Commit()
		return utils.SUCCESS_FLAG
	}
}

func updateSql(om orm.Ormer, info UserInfo) error {
	_, flag1 := om.QueryTable(UserInfoTBName()).Filter("login_name", info.LoginName).Update(orm.Params{
		"version":       orm.ColValue(orm.ColAdd, 1),
		"mobile":        info.Mobile,
		"edit_time":     info.EditTime,
		"user_name":     info.UserName,
		"status":        info.Status,
		"login_pwd":     info.LoginPwd,
		"salt":          info.Salt,
		"authority":     info.Authority,
		"total_amount":  info.TotalAmount,
		"usable_amount": info.UsableAmount,
		"frozen_amount": info.FrozenAmount,
		"api_key":       info.ApiKey,
		"pay_fee":       info.PayFee,
		"recharge_fee":  info.RechargeFee,
		"recharge_rate": info.RechargeRate,
	})
	return flag1
}
